package com.frank.loadinglibrary.common.element;

import com.frank.loadinglibrary.base.baseanimations.BaseAnimationController;
import com.frank.loadinglibrary.base.baseelement.BaseElement;
import com.frank.loadinglibrary.base.baseelement.IComponentCallback;
import com.frank.loadinglibrary.utils.Config;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.utils.geo.Point;

import java.util.ArrayList;

/**
 * @Description 旋转小球加载效果Element
 * @ClassName BallFadingElement.class
 * @program: loadinglibrary
 * @Author eric_shaw
 * @Date 2021/06/07
 * @Version 1.0
 **/
public class BallFadingElement extends BaseElement implements BaseAnimationController.IAnimationController<Animator> {
    /**
     * 画笔
     */
    private Paint mPaint;

    private static final int BALL_COLOR = Color.getIntColor("#efefef");

    /**
     * 组件回调接口
     */
    private IComponentCallback callback;
    /**
     * 可配置参数
     */
    private BallFadingParams params;

    private BallFadingElement(BallFadingParams param, IComponentCallback cl) {
        this.params = param;
        this.callback = cl;
    }

    @Override
    public BaseAnimationController.IAnimationController<Animator> initAnimationController() {
        return this;
    }

    @Override
    public void initPaint() {
        if (mPaint == null) {
            mPaint = new Paint();
            mPaint.setColor(new Color(BALL_COLOR));
            mPaint.setStyle(Paint.Style.FILL_STYLE);
            mPaint.setAntiAlias(true);
        }
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        float radius = getWidth() / params.radiusPercent;
        for (int i = 0; i < params.ballCount; i++) {
            canvas.save();
            Point point = calCircle(getWidth(), getHeight(), getWidth() / 2 - radius, i * (Math.PI * 2 / params.ballCount));
            canvas.translate(point.getPointX(), point.getPointY());
            canvas.scale(params.scaleFloats.get(i), params.scaleFloats.get(i));
            mPaint.setAlpha(params.alphas.get(i));
            if (params.colorPaletteOn) {
                Color currentColor = new Color(Color.getIntColor(params.colorPalette[i % params.colorPalette.length]));
                mPaint.setColor(currentColor);
            }
            canvas.drawCircle(0, 0, radius, mPaint);
            canvas.restore();
        }
    }

    @Override
    public void release() {
        super.release();

    }

    @Override
    public ArrayList<Animator> onCreateAnimators() {
        ArrayList<Animator> animators = new ArrayList<>();
        for (int i = 0; i < params.ballCount; i++) {
            final int index = i;
            AnimatorValue scaleAnim = new AnimatorValue();
            scaleAnim.setDuration(params.durtion);
            scaleAnim.setLoopedCount(-1);
            scaleAnim.setDelay(i * 120);
            scaleAnim.setValueUpdateListener((animatorValue, v) -> {
                if (v < 0.5f) {
                    params.scaleFloats.set(index, (float) (-1.2 * v + 1));
                } else {
                    params.scaleFloats.set(index, (float) (1.2 * v - 0.2));
                }
                if (callback != null) {
                    callback.reflushComponent();
                }
            });

            AnimatorValue alphaAnim = new AnimatorValue();
            alphaAnim.setDuration(params.durtion);
            alphaAnim.setLoopedCount(-1);
            alphaAnim.setDelay(i * 120);
            alphaAnim.setValueUpdateListener((animatorValue, v) -> {
                if (v < 0.5f) {
                    params.alphas.set(index, (-356 * v + 255) / 255);
                } else {
                    params.alphas.set(index, (356 * v - 101) / 255);
                }
                if (callback != null) {
                    callback.reflushComponent();
                }
            });
            if (params.enableScaleAnimator) {
                animators.add(scaleAnim);
            }
            if (params.enableAlphaAnimator) {
                animators.add(alphaAnim);
            }
            if (params.enableRotationAnimator && callback != null) {
                AnimatorProperty animatorProperty = callback.getAnimatorProperty();
                animatorProperty
                        .rotate(360)
                        .setDuration(params.durtion * 4)
                        .setLoopedCount(-1);
                animators.add(animatorProperty);
            }
        }
        return animators;
    }

    @Override
    public void onAnimationReset() {
        //do nothing because donot need to reset animation params
    }

    /**
     * 圆O的圆心为(a,b),半径为R,点A与到X轴的为角α.
     * 则点A的坐标为(a+R*cosα,b+R*sinα)
     * @param width
     * @param height
     * @param radius
     * @param angle
     * @return
     */
    Point calCircle(float width, float height, float radius, double angle) {
        float x = (float) (width / 2 + radius * (Math.cos(angle)));
        float y = (float) (height / 2 + radius * (Math.sin(angle)));
        return new Point(x, y);
    }


    /**
     * 构建者
     */
    public static class BallFadingBuild {

        private static final float SCALE = 1.0f;
        private static final float ALPHA = 1.0f;
        BallFadingParams params;
        IComponentCallback call;

        public BallFadingBuild(IComponentCallback c) {
            call = c;
            params = new BallFadingParams();
            for (int i = 0; i < params.ballCount; i++) {
                params.scaleFloats.add(SCALE);
                params.alphas.add(ALPHA);
            }
            params.colorPalette = Config.SKY_COLOR_ARRAY;
        }

        BallFadingElement.BallFadingBuild setBallCount(int count) {
            params.ballCount = count;
            if (params.ballCount > params.scaleFloats.size()) {
                params.scaleFloats.clear();
            }
            for (int i = 0; i < params.ballCount; i++) {
                params.scaleFloats.add(SCALE);
                params.alphas.add(ALPHA);
            }
            return BallFadingBuild.this;
        }

        BallFadingElement.BallFadingBuild setColorPaletteOn(boolean colorPaletteOn) {
            params.colorPaletteOn = colorPaletteOn;
            return this;
        }

        BallFadingElement.BallFadingBuild setColorPalette(String[] colors) {
            params.colorPalette = colors;
            return this;
        }

        BallFadingElement.BallFadingBuild setDurtion(int dur) {
            params.durtion = dur;
            return this;
        }

        BallFadingElement.BallFadingBuild setEnableAlphaAnimator(boolean alphaEnble) {
            params.enableAlphaAnimator = alphaEnble;
            return this;
        }


        BallFadingElement.BallFadingBuild setEnableScaleAnimator(boolean scaleEnble) {
            params.enableRotationAnimator = scaleEnble;
            return this;
        }

        BallFadingElement.BallFadingBuild setEnableRotationAnimator(boolean rorateEnble) {
            params.enableRotationAnimator = rorateEnble;
            return this;
        }

        BallFadingElement.BallFadingBuild setRadiusPercent(int radiu) {
            params.radiusPercent = radiu;
            return this;
        }

        public BallFadingElement build() {
            return new BallFadingElement(params, call);
        }
    }

    /***
     * 可配置参数类
     */
    public static class BallFadingParams {

        private boolean enableScaleAnimator = true;

        private boolean enableAlphaAnimator = false;

        private boolean enableRotationAnimator = false;

        private boolean colorPaletteOn = false;

        private int ballCount = 10;

        private int radiusPercent = 12;

        protected String[] colorPalette = Config.SKY_COLOR_ARRAY;

        ArrayList<Float> scaleFloats = new ArrayList<>();

        ArrayList<Float> alphas = new ArrayList<>();

        private int durtion = 1000;
    }


}
